/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: AsyncCommandThread.java,v $
 *
 */

package com.cidero.bridge.audiotron;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Logger;

import com.cidero.util.AsyncCommand;

/**
 * Thread to communicate with Audiotron asynchronously (avoid hanging
 * main process and allow for command timeout detection)
 */
public class AsyncCommandThread implements Runnable
{
  private static Logger logger = 
    Logger.getLogger("com.cidero.bridge.audiotron");

  ATronMediaRenderer mediaRenderer;
  
  public AsyncCommandThread( ATronMediaRenderer mediaRenderer )
  {
    this.mediaRenderer = mediaRenderer;
  }
  
  private Thread asyncCommThread = null;  // for clean shutdown via stop()
  
  public void start() {
    asyncCommThread = new Thread( this );
    asyncCommThread.start();
  }
  
  public void stop() {
    asyncCommThread = null;
  }
  
  public void run()
  {
    logger.fine("AsyncCommandThread: Running...");

    Thread thisThread = Thread.currentThread();

    AsyncCommand asyncCmd = mediaRenderer.getAsyncCommand();

    while( asyncCommThread == thisThread )
    {
      //
      // Get cmd from parent thread. Timeout after 4 sec and check 
      // for thread shutdown. Get audiotron status every 5 sec.
      //
      String url = (String)asyncCmd.receiveRequest( 5000 );
      
      if( url != null )
      {
        String response = sendCmd( url );

        if( ! asyncCmd.sendResponse( response, 4000 ) )
          logger.fine( "AsyncCommThread: Error forwarding response: " );
      }
      else
      {
        logger.finest( "AsyncCommThread: Timeout waiting for cmd: " );        
      }
    }

    logger.fine( "async thread shutting down... " );        
  }


  /**
   * Send the URL-encoded (HTTP) command and read back the response.
   * 
   * @return  response string or null if exception occurred during HTTP
   *          session 
   */
  public String sendCmd( String url )
  {
    try 
    {
      logger.fine( "sendCmd (async): Opening connection to: " + url );

      URL cmdURL = new URL( "http://" + 
                            mediaRenderer.getIPAddr() + ":" +
                            mediaRenderer.getPort() + url );

      URLConnection conn = cmdURL.openConnection();
      
      // Set any header properties
      conn.setRequestProperty("User-Agent", "UPnPBridge/1.0" );

      // Authorization header
      String auth = mediaRenderer.getUserName() + ":" + 
                    mediaRenderer.getPassword();
      conn.setRequestProperty("Authorization", 
                              "Basic " + 
                   new sun.misc.BASE64Encoder().encode( auth.getBytes() ) );

      // Send the request to the server (GET Request if URL is HTTP)
      logger.finest( "  Connecting" );
      conn.connect();
      
      logger.finest( "  ---HTTP Response Headers:----" );

      // List all the response headers from server
      for( int n = 0 ;; n++ )
      {
        String headerName = conn.getHeaderFieldKey( n );
        String headerValue = conn.getHeaderField( n );
        
        if( (headerName == null) && (headerValue == null) )
          break;  // No more headers

        if( headerName == null )
        {
          logger.finest("  Server HTTP version is: " + headerValue );
        }
        else
        {
          logger.finest( headerName + ": " + headerValue );
        }
      }

      // Read the response one line at a time (TODO: read in chunks instead)

			BufferedReader reader = new BufferedReader(
         new InputStreamReader( conn.getInputStream() ) );
			
      StringBuffer buf = new StringBuffer();
      String line;
      //      System.out.println("HTTP Response Body " );

      while( (line = reader.readLine()) != null )
      {
        buf.append( line );
        buf.append( "\n" );
      }

      return buf.toString();
    }
    catch( MalformedURLException e )
    {
      logger.warning("Malformed Audiotron Cmd URL: " + e );
      return null;
    }
		catch( Exception e )
    {
      logger.warning("sendCmd: Exception" + e );
      return null;
		}

  }
  
}
